﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace CommonEngine.Tools
{
    /// <summary>
    /// 有限并发级别的任务调度器
    /// 参考： www.cnblogs.com/x-xk/archive/2012/12/11/2804563.html
    /// </summary>
    public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
    {
        private static object executeLock = new object();
        /// <summary>
        /// Whether the current thread is processing work items.
        /// 当前线程是否正在处理工作项。
        /// </summary>
        [ThreadStatic]
        private static bool _currentThreadIsProcessingItems;
        /// <summary>
        /// The list of tasks to be executed.
        /// protected by lock(_tasks) 受保护的任务
        /// 要执行的任务列表
        /// </summary>
        private readonly LinkedList<Task> _tasks = new LinkedList<Task>();

        /// <summary>
        /// The maximum concurrency level allowed by this scheduler.
        /// 此调度器允许的最大并发级别
        /// </summary>
        private readonly int _maxDegreeOfParallelism;
        /// <summary>
        /// Whether the scheduler is currently processing work items.
        /// protected by lock(_tasks) 
        /// 计划程序当前是否正在处理工作项
        /// </summary>
        private int _delegatesQueuedOrRunning = 0;

        /// <summary>
        /// current executing number;
        /// 当前执行数
        /// </summary>
        public int CurrentCount { get; set; }

        /// <summary> 
        /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the specified degree of parallelism.
        /// 构造初始化
        /// </summary> 
        /// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param> 
        public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
        {
            if (maxDegreeOfParallelism < 1)
                throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");

            this._maxDegreeOfParallelism = maxDegreeOfParallelism;
        }

        /// <summary>
        /// Queues a task to the scheduler.
        /// 将任务排队到调度程序
        /// </summary> 
        /// <param name="task">The task to be queued.</param>
        protected sealed override void QueueTask(Task task)
        {
            // Add the task to the list of tasks to be processed. 将任务添加到要处理的任务列表中
            // If there aren't enough delegates currently queued or running to process tasks, schedule another. 
            // 如果当前排队或运行的委托不足以处理任务，请安排另一个
            lock (this._tasks)
            {
                Console.WriteLine("Task Count : {0} ", this._tasks.Count);
                this._tasks.AddLast(task);

                if (this._delegatesQueuedOrRunning < this._maxDegreeOfParallelism)
                {
                    //++this._delegatesQueuedOrRunning;
                    Interlocked.Increment(ref this._delegatesQueuedOrRunning);
                    //Interlocked.Add(ref this._delegatesQueuedOrRunning, 1);
                    NotifyThreadPoolOfPendingWork();
                }
            }
        }

        /// <summary> 
        /// Informs the ThreadPool that there's work to be executed for this scheduler. 
        /// 通知线程池此调度程序有要执行的工作
        /// </summary> 
        private void NotifyThreadPoolOfPendingWork()
        {
            //不安全队列用户工作项
            ThreadPool.UnsafeQueueUserWorkItem(a =>
            {
                // Note that the current thread is now processing work items. 
                // 请注意，当前线程正在处理工作项。
                // This is necessary to enable inlining of tasks into this thread. 
                // 这对于将任务内联到此线程中是必需的                
                _currentThreadIsProcessingItems = true;
                try
                {
                    // Process all available items in the queue. 处理队列中的所有可用项
                    while (true)
                    {
                        Task item;
                        lock (this._tasks)
                        {
                            // When there are no more items to be processed, note that we're done processing, and get out. 
                            // 当没有其他要处理的项目时，请注意我们已经完成处理，然后离开。
                            if (this._tasks.Count == 0)
                            {
                                //--this._delegatesQueuedOrRunning;
                                Interlocked.Decrement(ref this._delegatesQueuedOrRunning);
                                break;
                            }

                            // Get the next item from the queue 从队列中获取下一项
                            item = this._tasks.First.Value;
                            this._tasks.RemoveFirst();
                        }
                        // Execute the task we pulled out of the queue 
                        // 执行我们从队列中抽出的任务
                        base.TryExecuteTask(item);
                    }
                }
                finally
                {
                    // We're done processing items on the current thread 
                    // 我们已经处理完当前线程上的项目
                    _currentThreadIsProcessingItems = false;
                }
            }, null);
        }

        /// <summary>
        /// Attempts to execute the specified task on the current thread.
        /// 尝试在当前线程上执行指定的任务
        /// </summary>
        /// <param name="task">The task to be executed.</param>
        /// <param name="taskWasPreviouslyQueued">任务先前已排队</param>
        /// <returns>Whether the task could be executed on the current thread.</returns>
        protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            // If this thread isn't already processing a task, we don't support inlining 
            if (!_currentThreadIsProcessingItems)
                return false;

            // If the task was previously queued, remove it from the queue 
            if (taskWasPreviouslyQueued)
                TryDequeue(task);

            // Try to run the task. 
            return base.TryExecuteTask(task);
        }

        /// <summary>
        /// Attempts to remove a previously scheduled task from the scheduler.
        /// 尝试从计划程序中删除以前计划的任务
        /// </summary> 
        /// <param name="task">The task to be removed.</param> 
        /// <returns>Whether the task could be found and removed.</returns> 
        protected sealed override bool TryDequeue(Task task)
        {
            lock (this._tasks)
                return _tasks.Remove(task);
        }

        /// <summary>
        /// Gets the maximum concurrency level supported by this scheduler.
        /// 获取此调度器支持的最大并发级别
        /// </summary> 
        public sealed override int MaximumConcurrencyLevel { get { return this._maxDegreeOfParallelism; } }

        /// <summary>
        /// Gets an enumerable of the tasks currently scheduled on this scheduler.
        /// 获取此计划程序上当前计划的任务的可枚举性
        /// </summary> 
        /// <returns>An enumerable of the tasks currently scheduled.</returns> 
        protected sealed override IEnumerable<Task> GetScheduledTasks()
        {
            bool lockTaken = false;
            try
            {
                Monitor.TryEnter(_tasks, ref lockTaken);
                if (lockTaken)
                    return this._tasks.ToArray();
                else
                    throw new NotSupportedException();
            }
            finally
            {
                if (lockTaken)
                    Monitor.Exit(this._tasks);
            }
        }
    }
}
